<template>
  <div class="connection-panel" tabindex="0" @keydown="onPanelKeydown">
    <div class="connection-panel--header">
      <span>连接列表</span>
      <el-input v-model.trim="filters.dbname" class="dbname-filter" ref="filter" @focus="filters.focus = true"
                @blur="filters.focus = false" placeholder="过滤数据库" size="small" clearable></el-input>
      <div class="connection-panel--buttons">
        <el-button size="small" @click="dialogVisible = true" title="新建连接">
          <el-icon>
            <Plus />
          </el-icon>
        </el-button>
      </div>
    </div>
    <div class="connection-panel--list">
      <ul class="connection-items">
        <li class="connection-item" :class="{
            active: connection.active,
            expanded: connection.expanded,
            opened: connection.opened,
          }" v-for="connection in connections" :key="connection.label">
          <div class="connection-node" @click="onConnectionClick(connection)" :title="getConnectionTitle(connection)">
            <el-popover placement="right" trigger="hover">
              <template #reference>
                <span class="connection-name">
                  <el-icon>
                    <Connection />
                  </el-icon>
                  <i class="el-icon-link" v-loading="connection.loading"></i>
                  <span class="connection-label">
                    {{ connection.label }}
                    <span v-if="connection.remark">({{ connection.remark }})</span>
                  </span>
                  <span class="opened-flag" v-show="connection.opened">
                    <el-icon v-show="connection.expanded">
                      <CaretBottom />
                    </el-icon>
                    <el-icon v-show="!connection.expanded">
                      <CaretRight />
                    </el-icon>
                  </span>
                </span>
              </template>
              <template #default>
                <div class="connection-buttons">
                  <div style="font-weight: bold">连接管理</div>
                  <el-link @click="onConnectionClick(connection, true)" v-show="!connection.opened">
                    <el-icon>
                      <FolderOpened />
                    </el-icon>
                    <span>打开</span>
                  </el-link>
                  <el-link @click="loadDatabase(connection)" v-show="connection.opened">
                    <el-icon>
                      <Refresh />
                    </el-icon>
                    <span>刷新</span>
                  </el-link>
                  <el-link @click="onCloseConnection(connection)" v-show="connection.opened">
                    <el-icon>
                      <CircleClose />
                    </el-icon>
                    <span>关闭</span>
                  </el-link>
                  <el-link @click="onEditConnection(connection)" v-show="!connection.opened">
                    <el-icon>
                      <Edit />
                    </el-icon>
                    <span>编辑</span>
                  </el-link>
                  <el-link @click="onCopyConnection(connection)">
                    <el-icon>
                      <CopyDocument />
                    </el-icon>
                    <span>复制</span>
                  </el-link>
                  <el-link @click="onRemoveConnection(connection)" v-show="!connection.opened">
                    <el-icon>
                      <Remove />
                    </el-icon>
                    <span>移除</span>
                  </el-link>
                </div>
              </template>
            </el-popover>
          </div>
          <ul class="database-items" v-if="connection.databases && connection.databases.length"
              v-show="connection.expanded">
            <li class="database-item" :class="{
                active: database.active,
                expanded: database.expanded,
                opened: database.opened,
              }" v-for="database in connection.databases"
                v-show="!filters.dbname || database.name.toLowerCase().indexOf(filters.dbname.toLowerCase()) !== -1"
                :key="database.name">
              <div class="database-name" @click="onDatabaseClick(database)" :title="database.name">
                <el-icon>
                  <Coin />
                </el-icon>
                <span class="database-label">{{ database.name }}</span>
              </div>
            </li>
          </ul>
        </li>
      </ul>
    </div>
    <el-dialog title="连接信息" v-model="dialogVisible" :close-on-click-modal="false" :close-on-press-escape="false"
               width="600px" destroy-on-close>
      <connection-dialog :data="editConnection" @close="onDialogClose" />
    </el-dialog>
  </div>
</template>
<script setup>
import ConnectionDialog from '@/components/connection/ConnectionDialog.vue'
import {
  CaretBottom,
  CaretRight,
  CircleClose,
  Coin,
  Connection,
  CopyDocument,
  Edit,
  FolderOpened,
  Plus, Refresh,
  Remove
} from '@element-plus/icons-vue'
</script>
<script>
import { ElMessage, ElMessageBox } from 'element-plus'
import { mapState } from 'vuex'
import bus from '@/assets/scripts/bus'
import apis from '@/assets/apis'

export default {
  name: 'ConnectionPanel',
  props: {},
  data() {
    return {
      dialogVisible: false,
      lastClick: {
        item: null,
        // connection/database
        type: null,
        time: 0
      },
      editConnection: null,
      filters: {
        dbname: '',
        focus: false
      }
    }
  },
  mounted() {
    this.loadConnections()
  },
  methods: {
    onPanelKeydown() {
      if (this.dialogVisible) {
        return
      }
      if (this.filters.focus) {
        return
      }
      // this.filters.dbname = e.key
      this.$refs.filter.focus()
    },
    getConnectionTitle(connection) {
      return `${connection.host}:${connection.port}\n${connection.remark}`
    },
    updateLastClick(type, data) {
      const lastTime = this.lastClick.time
      const now = new Date().getTime()
      if (!lastTime) {
        data.active = true
        this.lastClick.item = data
        this.lastClick.time = now
        this.lastClick.type = type
        return false
      }
      const lastItem = this.lastClick.item
      const lastType = this.lastClick.type
      if (lastItem !== data || lastType !== type) {
        lastItem.active = false
        data.active = true
        this.lastClick.item = data
        this.lastClick.time = now
        this.lastClick.type = type
        return false
      }
      // 500 毫秒内点击，认为是双击
      if (now - this.lastClick.time > 500) {
        this.lastClick.time = now
        return false
      }
      this.lastClick.item.expanded = !this.lastClick.item.expanded
      if (this.lastClick.item.opened && type === 'connection') {
        return false
      }
      this.lastClick.item.opened = true
      return true
    },
    onDatabaseClick(data) {
      const isDblClick = this.updateLastClick('database', data)
      const args = { database: data.name, connection: data.connection.label }
      if (!isDblClick) {
        this.$nextTick(() => {
          bus.emit('database-selected', args)
        })
        return
      }
      this.$nextTick(() => {
        bus.emit('database-opened', args)
      })
    },
    // onConnectionClose(connection) {
    //
    // },
    onConnectionClick(data, force) {
      if (force) {
        this.updateLastClick('connection', data)
      }
      if (!this.updateLastClick('connection', data)) {
        return
      }
      this.loadDatabase(data)
    },
    loadDatabase(connection) {
      this.$store.commit('updateGlobalMsg', '正在加载信息...')
      connection.loading = true

      apis.dbm.connection.connect(connection).then(data => {
        const databaseList = data[0].data.map(item => ({
          name: item[0],
          opened: false,
          expanded: false,
          connection
        }))
        databaseList.sort((a, b) => a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1)
        this.$store.commit('updateGlobalMsg', '加载完成')
        this.$store.commit('updateDatabaseList', {
          list: databaseList,
          label: connection.label
        })
        this.$emit('close')
      }).catch(e => {
        this.lastClick.item.opened = false
        this.$store.commit('updateGlobalMsg', `错误： ${e.message}`)
        ElMessage.error(e.message)
      }).finally(() => {
        connection.loading = false
      })
    },
    loadConnections() {
      apis.dbm.connection.getAll().then(data => {
        data.forEach(con => {
          con.opened = false
          con.expanded = false
          con.loading = false
          con.databases = []
        })
        this.$store.commit('setConnections', data)
        this.$emit('close')
      }).catch(e => {
        this.msg = e.message
      })
    },
    onCloseConnection(connection) {
      connection.expanded = false
      connection.opened = false
    },
    onEditConnection(connection) {
      this.editConnection = {
        ...connection,
        databases: []
      }
      this.dialogVisible = true
    },
    onCopyConnection(connection) {
      this.editConnection = {
        ...connection,
        label: connection.label + '_1',
        databases: [],
        id: null
      }
      this.dialogVisible = true
    },
    onRemoveConnection(connection) {
      ElMessageBox.confirm(`确定要移除连接 ${connection.label} 吗？`).then(() => {
        apis.dbm.connection.remove(connection.id).then(() => {
          this.$store.commit('removeConnection', connection)
        }).catch(e => {
          ElMessage.error('移除连接失败:' + e.message)
        }).finally(() => {
        })
      }).catch(() => {
      })
    },
    onDialogClose() {
      this.dialogVisible = false
      this.editConnection = null
    }
  },
  computed: mapState({
    connections: state => state.connections
  })
}
</script>


<style lang="less" scoped>
.connection-panel {
  position: relative;
  height: 100%;
  //background-color: #ffffff;
  color: #333;
  outline: none;
}

.connection-panel--header {
  padding: 5px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.dbname-filter {
  width: 120px;
  flex: 1 1;
  margin: 0 10px;
}

.connection-panel--buttons {
  text-align: right;

  .el-button {
    font-size: large;
  }
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

li {
  i {
    margin-right: 2px;
  }
}

.connection-items {
  padding: 5px;
}

.connection-panel--list {
  padding: 5px;
  font-size: 14px;
  box-sizing: border-box;
  overflow: auto;
  position: absolute;
  top: 40px;
  left: 0;
  width: 100%;
  bottom: 0;
  user-select: none;
}

.connection-node {
  color: var(--connection-color);
  cursor: pointer;
  padding: 5px 0;

  &:hover {
    .connection-name {
      color: var(--connection-hover-color);
    }
  }
}

.database-name {
  color: var(--connection-color);
  cursor: pointer;
  padding: 5px 0;
  white-space: nowrap;
  white-space: nowrap;
  word-break: keep-all;
  overflow: hidden;
  text-overflow: ellipsis;

  .el-icon,
  database-label {
    vertical-align: -2px;
  }

  &:hover {
    color: var(--connection-hover-color);
  }
}

.connection-node {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.connection-item {
  &.active {
    .connection-name {
      color: var(--connection-hover-color);
    }
  }
}

.connection-name {
  white-space: nowrap;
  word-break: keep-all;
  overflow: hidden;
  text-overflow: ellipsis
}

.database-item {
  &.active {
    .database-name {
      color: var(--connection-hover-color);
    }
  }
}

.database-items {
  margin-left: 10px;
}

.database-item {
  padding: 2px 0;
}

.opened-flag {
  color: var(--connection-open-color);
}

.connection-buttons {
  // margin: 0 5px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;

  .el-link {
    word-break: keep-all;
  }

  i {
    margin-right: 3px;
    font-size: 14px;
  }
}

.el-icon-edit {
  color: rgb(10, 6, 0);
}

.el-icon-remove {
  color: red;
}
</style>
